# ///////////////////////////////////////////////////////////////
#
# BY: WANDERSON M.PIMENTA
# PROJECT MADE WITH: Qt Designer and PySide6
# V: 1.0.0
#
# This project can be used freely for all uses, as long as they maintain the
# respective credits only in the Python scripts, any information in the visual
# interface (GUI) can be modified without any implication.
#
# There are limitations on Qt licenses if you want to use your products
# commercially, I recommend reading them on the official website:
# https://doc.qt.io/qtforpython/licenses.html
#
# ///////////////////////////////////////////////////////////////

import sys
import os
import time
import webbrowser
# import multiprocessing
# from PySide6.QtCore import QProcess
# import logging
# logging.
# IMPORT / GUI AND MODULES AND WIDGETS
# ///////////////////////////////////////////////////////////////
from modules import *
# from modules.set_alarm_ui import Ui_Dialog_Set_Alarm
from modules.ui_functions import *
# from modules.ui_functions import MyLoginDialog
from widgets import *
from PySide6.QtMultimedia import QSoundEffect
from openpyxl import Workbook
from openpyxl.utils import get_column_letter
os.environ["QT_FONT_DPI"] = "96" # FIX Problem for High DPI and Scale above 100%

# SET AS GLOBAL WIDGETS
# ///////////////////////////////////////////////////////////////
widgets = None





class NumericSortProxyModel(QSortFilterProxyModel):
    '''重写数字比较'''
    def __init__(self):
        super().__init__()
        self.setDynamicSortFilter(True)
        self.setFilterKeyColumn(-1)
        self.filters = {}
        self.mode ='column'
    def lessThan(self, left, right):
        # 获取原始数据模型中的值
        left_data = self.sourceModel().data(left)
        right_data = self.sourceModel().data(right)
        
        # 尝试转换为数值比较
        try:
            left_num = float(left_data)
            right_num = float(right_data)
            return left_num < right_num
        except ValueError:
            # 如果转换失败，回退到字符串比较
            return super().lessThan(left, right)
    def setFilter(self,column,text):
        self.filters[column] = text
        self.invalidateFilter()
    def filterAcceptsRow(self, source_row, source_parent):
        if self.mode == 're':
            return super().filterAcceptsRow(source_row,source_parent)
        model  = self.sourceModel()
        for column, text in self.filters.items():
            index = model.index(source_row, column, source_parent)
            data = model.data(index, Qt.DisplayRole)
            if text.lower() not in str(data).lower():
                return False
        return True





class MainWindow(QMainWindow):
    
    def __init__(self):
        QMainWindow.__init__(self)
        self.ori_user_init = {
            'alarm_sound_enable':False,
            'alarm_enable':False
        }
        self.user_init = {
            'alarm_sound_enable':False,
            'alarm_enable':False
        }

        # SET AS GLOBAL WIDGETS
        # ///////////////////////////////////////////////////////////////
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)
        global widgets
        widgets = self.ui

        # USE CUSTOM TITLE BAR | USE AS "False" FOR MAC OR LINUX
        # ///////////////////////////////////////////////////////////////
        Settings.ENABLE_CUSTOM_TITLE_BAR = True

        # APP NAME
        # ///////////////////////////////////////////////////////////////
        title = "暖立方客户端-HEAT CUBE"
        description = "滨州热力有限公司-暖立方客户端"
        # APPLY TEXTS
        self.setWindowTitle(title)
        widgets.titleRightInfo.setText(description)
        # 左侧设置按钮隐藏
        widgets.toggleLeftBox.hide()
        # TOGGLE MENU
        # ///////////////////////////////////////////////////////////////
        widgets.toggleButton.clicked.connect(lambda: UIFunctions.toggleMenu(self, True))

        # SET UI DEFINITIONS
        # ///////////////////////////////////////////////////////////////
        UIFunctions.uiDefinitions(self)

        # QTableWidget PARAMETERS
        # ///////////////////////////////////////////////////////////////
        widgets.tableWidget.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)

        # BUTTONS CLICK
        # ///////////////////////////////////////////////////////////////

        # LEFT MENUS
        widgets.btn_home.clicked.connect(self.buttonClick)
        widgets.btn_source.clicked.connect(self.buttonClick)
        widgets.btn_station.clicked.connect(self.buttonClick)
        widgets.btn_netbalance.clicked.connect(self.buttonClick)
        widgets.btn_center.clicked.connect(self.buttonClick)

        widgets.btn_alarm.clicked.connect(self.buttonClick)
        widgets.btn_history.clicked.connect(self.buttonClick)

        widgets.btn_userdefine.clicked.connect(self.buttonClick)
        widgets.btn_logs.clicked.connect(self.buttonClick)
        # widgets.btn_save.clicked.connect(self.buttonClick)
        # widgets.btn_save.clicked.connect(self.buttonClick)
        # widgets.btn_save.clicked.connect(self.buttonClick)
        # widgets.btn_save.clicked.connect(self.buttonClick)
        widgets.btn_login.clicked.connect(self.login_ui)
        widgets.btn_widgets.clicked.connect(self.buttonClick)

        widgets.btn_exit.hide()
        widgets.btn_netbalance.hide()
        widgets.btn_history.hide()
        widgets.userdefine.hide()
        widgets.btn_widgets.hide()
        widgets.btn_print.hide()
        widgets.btn_message.hide()
        widgets.btn_alarm_export.hide()
        # widgets.btn_process.hide()
        

        # EXTRA LEFT BOX
        def openCloseLeftBox():
            UIFunctions.toggleLeftBox(self, True)
        # widgets.toggleLeftBox.clicked.connect(openCloseLeftBox)
        widgets.extraCloseColumnBtn.clicked.connect(openCloseLeftBox)

        # EXTRA RIGHT BOX
        def openCloseRightBox():
            UIFunctions.toggleRightBox(self, True)
        widgets.settingsTopBtn.clicked.connect(openCloseRightBox)

        # SHOW APP
        # ///////////////////////////////////////////////////////////////
        self.show()

        # SET CUSTOM THEME
        # ///////////////////////////////////////////////////////////////
        useCustomTheme = False
        themeFile = "themes\\py_dracula_light.qss"

        # SET THEME AND HACKS
        if useCustomTheme:
            # LOAD AND APPLY STYLE
            UIFunctions.theme(self, themeFile, True)

            # SET HACKS
            AppFunctions.setThemeHack(self)

        # SET HOME PAGE AND SELECT MENU
        # ///////////////////////////////////////////////////////////////
        self.setMouseTracking(True)
        widgets.stackedWidget.setCurrentWidget(widgets.home)
        # widgets.btn_home.setStyleSheet(UIFunctions.selectMenu(widgets.btn_home.styleSheet()))
        widgets.btn_station.setStyleSheet(UIFunctions.selectMenu(widgets.btn_station.styleSheet()))

        self.alarm_timer = QTimer()
        self.alarm_timer.setInterval(20000)
        self.alarm_thread = UserAlarm(self)
        self.weather = Weather(self)
        self.weather.run()
        # self.alarm_timer.start()
        self.alarm_timer.timeout.connect(self.alarm_thread.run)

        
        

        self.station_model = QStandardItemModel()
        self.source_model = QStandardItemModel()
        self.netbalance_model = QStandardItemModel()

        self._station_proxy_model = NumericSortProxyModel()
        self._station_proxy_model.setFilterCaseSensitivity(Qt.CaseSensitivity.CaseInsensitive)
        self._source_proxy_model = NumericSortProxyModel()
        self._netbalance_proxy_model = NumericSortProxyModel()

        self._station_proxy_model.setSourceModel(self.station_model)
        self._source_proxy_model .setSourceModel(self.source_model )
        self._netbalance_proxy_model .setSourceModel(self.netbalance_model )

        self.source_timer = QTimer(interval=5000)
        self.station_timer= QTimer(interval=15000)
        self.station_updata = UpdataThread(model=self.station_model,view=self.ui.tv_station,proxymodel=self._station_proxy_model,type='getall')
        self.source_updata = UpdataThread(model=self.source_model,view=self.ui.tv_source,proxymodel=self._source_proxy_model,type='getallsource')
        self.station_updata.start()
        self.source_updata.start()
        self.source_timer.timeout.connect(lambda : self.update_data(task_name='source'))
        self.station_timer.timeout.connect(lambda : self.update_data(task_name='system'))
        self.source_timer.start()
        self.station_timer.start()

        # widgets.pushButton.clicked.connect(self.start_alarm) 
        widgets.commandLinkButton.clicked.connect(lambda : self.effect.stop())

        # self.ui.tv_station.setSortingEnabled(True)
        # self.ui.tv_source.setSortingEnabled(True)
        self.ui.tv_source.customContextMenuRequested.connect(lambda x :self.showmenu(x,self.ui.tv_source) )
        self.ui.tv_station.customContextMenuRequested.connect(lambda x :self.showmenu(x,self.ui.tv_station) )
        self.ui.tv_net_detail.customContextMenuRequested.connect(lambda x :self.showmenu(x,self.ui.tv_station) )
        self.ui.btn_source_export.clicked.connect(lambda : self.export(excel='source'))
        self.ui.le_serch.textChanged.connect(self.re_filter)

        self.ui.tv_station.doubleClicked.connect(lambda x:self.process_jump(x,self.ui.tv_station))
        widgets.btn_station_export.clicked.connect(lambda : self.export())
        widgets.cb_source.currentIndexChanged.connect(self.source_filter)

        widgets.cb_company.currentTextChanged.connect(self.company_filter)
        
        widgets.cb_use_type.currentIndexChanged.connect(self.use_filter)

        widgets.cb_sup_type.currentIndexChanged.connect(self.sup_filter)

        # widgets.cb_use_type.currentIndexChanged.connect(self.filter_type)
        
        self.station_updata.th_signal.connect(lambda data:self.modellize(data,task_name='station'))
        self.source_updata.th_signal.connect(lambda data:self.modellize(data,task_name='source'))
        widgets.btn_station_reset.clicked.connect(self.filter_default)
        widgets.btn_userdefined_list.clicked.connect(self.user_defined_group)
        widgets.btn_logout.clicked.connect(self.logout_ui)
        widgets.btn_print.clicked.connect(lambda : print(self.user_init))
        widgets.cb_group.currentTextChanged.connect(self.change_group)
        self.update_group()
        
        self.alarm_thread.alarm_signal.connect(self.get_alarm)
        widgets.btn_station_serch.clicked.connect(self.station_visable)
        widgets.tab_station.currentChanged.connect(self.stop_process_thread)
        # widgets.pushButton_2.clicked.connect(lambda :self.testapi())
        # 中心站按钮点击后切换界面并且启动中心站线程
        widgets.btn_center.clicked.connect(self.center_thread)
        widgets.btn_enable_alarm.clicked.connect(self.set_alarm_enable)
        widgets.btn_alarm_sound_enable.clicked.connect(self.set_alarm_sound_enable)
        self.center_btn()
        
        widgets.btn_udf_oa.clicked.connect(lambda:webbrowser.open(url='http://192.168.6.132:89/seeyon/'))
        widgets.btn_udf_rep.clicked.connect(lambda:webbrowser.open(url='http://192.168.6.71:8080/webroot/decision/'))
        widgets.btn_udf_web.clicked.connect(lambda:webbrowser.open(url='http://192.168.5.116:8087/#/login?redirect=%2Fdashboard'))
        widgets.guoji_btn_rep.clicked.connect(lambda:webbrowser.open('http://192.168.6.71:8080/webroot/decision/'))
        widgets.youju_btn_rep.clicked.connect(lambda:webbrowser.open('http://192.168.6.71:8080/webroot/decision/'))
        widgets.yaguang_btn_rep.clicked.connect(lambda:webbrowser.open('http://192.168.6.71:8080/webroot/decision/'))
        widgets.tianhong_btn_rep.clicked.connect(lambda:webbrowser.open('http://192.168.6.71:8080/webroot/decision/'))
        widgets.weather_img.deleteLater()
        widgets.btn_operate_log_serch.clicked.connect(self.get_operate_log)
        widgets.btn_alarm_serch.clicked.connect(self.get_alarm_log)

        # 默认跳转站点数据界面
        widgets.stackedWidget.setCurrentIndex(2)
        # widgets.btn_message_4.clicked.connect(self.play_alarm_sound)
###################################################################################################################################        
# user define or test function####################################################################################################
    def get_alarm_log(self):
        date = {
            "start_date":self.ui.date_alarm_start_time.dateTime().toString("yyyy-MM-dd HH:mm:ss"),
            "stop_date":self.ui.date_alarm_end_time.dateTime().toString("yyyy-MM-dd HH:mm:ss"),
            'username' : self.user_init.get('username')
        }
        res = requests.post(url=Settings.APPURL+'/log/alarm',json=date).json()
        model = QStandardItemModel()
        for i in res:
            row = []
            for j in i:
                row.append(QStandardItem(j))
            model.appendRow(row)
        model.setHorizontalHeaderLabels(['id','报警点位','站点名称','系统名称','报警变量','报警时间','报警高低限','报警值'])
        self.ui.tw_alarm_his.setModel(model)
        self.ui.tw_alarm_his.resizeColumnsToContents()


    def get_operate_log(self):
        date = {
            "start_date":self.ui.dte_operate_log_start_date.dateTime().toString("yyyy-MM-dd HH:mm:ss"),
            "stop_date":self.ui.dte_operate_log_stop_date.dateTime().toString("yyyy-MM-dd HH:mm:ss"),
        }
        res = requests.post(url=Settings.APPURL+'/log/operate',json=date).json()
        model = QStandardItemModel()
        for i in res:
            row = []
            for j in i:
                row.append(QStandardItem(j))
            model.appendRow(row)
        model.setHorizontalHeaderLabels(['id','用户名','用户ip地址','操作时间','主机名称','操作类型','详细操作','站点编号','站点名称','站点机组','详细操作','站点简称','设置账号'])
        self.ui.tv_operate_log.setModel(model)
        self.ui.tv_operate_log.resizeColumnsToContents()

        
    def testapi(self):
        # 1组成想要控制点位的kv
        # 2发送
        # 3获得控制结果

        d = {
            'name':"json",
            "num":5
        }

        res = requests.post(url=f'{Settings.APPURL}/api117/control',json=d)

        # print(res.json())


    def set_alarm_sound_enable(self):
        '''设置报警声音开关：不登陆不能触发'''
        # print(self.user_init)
        if not self.user_init.get('uuid'):
            self.statusbar_text('请先登录！')
            return
        if self.user_init.get('alarm_sound_enable'):
            self.user_init['alarm_sound_enable'] = False
            self.ui.btn_alarm_sound_enable.setText('报警声音:关')
            
            self.ui.btn_alarm_sound_enable.setStyleSheet(u"background-image: url(:/icons/images/icons/alarm_sound_close.png);")
        else :
            self.user_init['alarm_sound_enable'] = True
            self.ui.btn_alarm_sound_enable.setText('报警声音:开')
            self.ui.btn_alarm_sound_enable.setStyleSheet(u"background-image: url(:/icons/images/icons/alarm_sound_open.png);")
        # print(self.user_init)

    def set_alarm_enable(self):
        '''设置报警开关：不登陆不能触发'''
        # print(self.user_init)
        if not self.user_init.get('uuid'):
            self.statusbar_text('请先登录！')
            return
        if self.user_init.get('alarm_enable') :

            self.user_init['alarm_enable'] = False
            self.ui.btn_enable_alarm.setStyleSheet(u"background-image: url(:/icons/images/icons/alarm-white.png);")
            widgets.tw_alarm_now.model().clear()
            self.alarm_timer.stop()
            widgets.btn_alarm.setStyleSheet('background-image: url(:/icons/images/icons/alarm-white.png);')
            
        else:
            self.user_init['alarm_enable'] = True
            self.ui.btn_enable_alarm.setStyleSheet(u"background-image: url(:/icons/images/icons/alarm-rad.png);")
            self.alarm_timer.start()



    def center_thread(self):
        '''中心站线程启动'''
        try:
            id(self.centerthread)
        except Exception as e:
            self.centerthread = CenterProcessThread(self)
            self.centerthread.run()
    def stop_process_thread(self,i):
        '''删除工艺图线程：切换工艺图界面时会删除上一个正在运行的线程'''
        try:
            if ( i == 0 ) and (self.process_thread) :
                del self.process_thread
        except Exception as e:
            pass
            
    def station_visable(self):
        '''隐藏或者显示站点隐藏列的按钮'''
        if widgets.btn_station_serch.text() =='显示隐藏列':
            for i in range(0,9):
                widgets.tv_station.setColumnHidden(i,False)
            widgets.btn_station_serch.setText('隐藏')
        else:
            for i in range(0,9):
                widgets.tv_station.setColumnHidden(i,True)
            widgets.btn_station_serch.setText('显示隐藏列')

        
    def get_alarm(self,alarm_group:list):
        '''获得报警，并将报警信息填入表格'''
        # print('alarm_list',alarm_group)
        if not self.user_init.get('alarm_enable'):
            return
        if (not alarm_group) and widgets.tw_alarm_now.model():
            # 如果没有报警，就清空表格
            widgets.btn_alarm.setStyleSheet('background-image: url(:/icons/images/icons/alarm-white.png);')

            widgets.tw_alarm_now.model().clear()
            return
        self.alarm_model = QStandardItemModel()
        labels = ['报警代码','站点名称','系统名称','报警点位','报警时间','报警讯息','报警值']
        self.alarm_model.setHorizontalHeaderLabels(labels)
        for i in alarm_group:
            l = list(map(QStandardItem,i))
            self.alarm_model.appendRow(l)
        widgets.tw_alarm_now.setModel(self.alarm_model)
        widgets.tw_alarm_now.resizeColumnsToContents()
        self.play_alarm_sound()
        # print(alarm_group)

        widgets.btn_alarm.setStyleSheet('background-image: url(:/icons/images/icons/alarm-rad.png);')
        self.statusbar_text(text='出现报警！！！')

    def change_group(self,groupname):
        # print('groupname',groupname)
        if not groupname:
            return
        groups = {
            '全部':0,
            '一分公司':1,
            '二分公司':2,
            '三分公司':3,
            '四分公司':4

        }

        id = groups.get(groupname)
        if id == 0:
            self.station_updata.modify_usergroup(id)
        elif not id:
            id = self.user_init.get('group').get(groupname)
        self.station_updata.modify_usergroup(id)
        self.station_model.clear()
        widgets.tv_station.setModel(None)
        # widgets.tv_station.setModel(self._station_proxy_model)

    def user_defined_group(self):

        if not self.user_init.get('username'):
            self.statusbar_text('请登录后打开配置！！！')
            return
        listui = MyUserGroupDialog(self.user_init)
        listui.signal_usergroup.connect(self.update_group)
        
        res = listui.exec()
    def update_group(self,user_init = {}):
        # 如果登录就获得用户的分组，如果没有登录就获得默认的五个分组
        # print(user_init)
        if user_init :
            self.user_init = user_init
        if group := self.user_init.get('group'):
        # 获得用户自己的分组
            
            _list = list(group.keys())
            sort_dict = {'全部':1,'一分公司':2,'二分公司':3,'三分公司':4,'四分公司':5}
            _list.sort(key=lambda x:6 if sort_dict.get(x)==None else sort_dict.get(x))
            self.ui.cb_group.clear()
            self.ui.cb_group.addItems(_list)
        else:
            self.ui.cb_group.clear()
            self.ui.cb_group.addItems(['全部','一分公司','二分公司','三分公司','四分公司'])
        
        
        # 更新combobox


        # pass
    def export(self,excel='station'):
        # x = time.time()
        s ='供热系统运行参数' if excel =='station' else '热源运行参数'
        x = time.strftime(f'{s}-%Y年%m月%d日%H时%M分',time.localtime())
        # 获取文件保存路径
        file_path, _ = QFileDialog.getSaveFileName(
            self, "保存文件", x, "Excel 文件 (*.xlsx)"
        )
        if not file_path:
            return  # 用户取消保存
 
        # 创建 Excel 工作簿
        wb = Workbook()
        ws = wb.active
        ws.title = "sheet1"
        
        model = self._station_proxy_model
        # 写入表头和数据
        header = widgets.tv_station.horizontalHeader()
        if excel == 'source':
            model = self._source_proxy_model
            header = widgets.tv_source.horizontalHeader()

        collist = []
        headers = []
        for i in range(model.columnCount()):
            if not header.isSectionHidden(i):
                collist.append(i)
                headers.append(model.headerData(i, Qt.Horizontal, Qt.DisplayRole))
        ws.append(headers)
        for row_idx in range(model.rowCount()):
            for a,b in enumerate(collist):
                # 获取单元格数据
                index = model.index(row_idx, b)
                cell_data = model.data(index, Qt.DisplayRole)
                # 写入 Excel
                ws.cell(row=row_idx + 2, column=a + 1, value=cell_data)

        try:
            wb.save(file_path)
            print(f"文件已保存至: {file_path}")
        except Exception as e:
            print(f"保存失败: {e}")
    def login_ui(self):
        # 登录内容返回给初始化用户字典
        if self.user_init.get('uuid'):
            return
        login = MyLoginDialog()
        login.signal_login.connect(lambda x : self.init_user_dict(x))
        res = login.exec()
    def logout_ui(self):
        self.user_init = self.ori_user_init
        self.ui.btn_login.setText(f'账号登录')
        self.ui.btn_enable_alarm.setStyleSheet(u"background-image: url(:/icons/images/icons/alarm-white.png);")
        widgets.btn_alarm.setStyleSheet('background-image: url(:/icons/images/icons/alarm-white.png);')
        self.ui.btn_alarm_sound_enable.setStyleSheet(u"background-image: url(:/icons/images/icons/alarm_sound_close.png);")
        self.update_group()
        msg = QMessageBox.information(None,'退出','退出成功!')
        
        # msg.setWindowTitle('退出')
        # msg.setText('退出成功！')
        # msg.exec()
    def init_user_dict(self,res):
        self.user_init  = {**res,**self.user_init}
        self.alarm_thread.set_alarm_group()
        self.statusbar_text(f"登陆成功：{res.get('username')}")
        self.ui.btn_login.setText(f"登录账号：{res.get('username')}")
        
        self.update_group()
    def set_station_row(self):
        # print(self.ui.tv_station.rowHeight(0))
        # return
        for i in range(self.ui.tv_station.model().rowCount()):

            self.ui.tv_station.setRowHeight(i,50)
    def use_filter(self,useid):
        """过滤用暖类型"""
        # print(useid)
        if useid == 0 and self._station_proxy_model.filters.get(8):
            del self._station_proxy_model.filters[8]
            self._station_proxy_model.invalidateFilter()
        else:
            self._station_proxy_model.mode='column'
            self._station_proxy_model.setFilter(8,str(useid))
        self.set_station_row()
    def sup_filter(self,supid):
        """过滤站点类型"""
        # print(commpany_text)
        if supid == 0 and self._station_proxy_model.filters.get(5):
            del self._station_proxy_model.filters[5]
            self._station_proxy_model.invalidateFilter()
        else:
            l = [0,1,4,5]
            self._station_proxy_model.mode='column'
            self._station_proxy_model.setFilter(5,str(l[supid]))       
        self.set_station_row()
    def re_filter(self, text):
        """搜索框使用正则"""
        self._station_proxy_model.mode='re'
        self._station_proxy_model.setFilterRegularExpression(text)
        # self._station_proxy_model.mode='column'
        
    def update_data(self,task_name='source'):
        sender = self.sender()
        if  task_name == 'source':
            self.source_updata.start()

        elif task_name =='system':
            self.station_updata.start()
    def company_filter(self,commpany_text):
        """监控数据过滤分公司"""
        # print(commpany_text)
        if commpany_text =='全部分公司' and self._station_proxy_model.filters.get(7):
            del self._station_proxy_model.filters[7]
            self._station_proxy_model.invalidateFilter()
        else:
            self._station_proxy_model.mode='column'
            self._station_proxy_model.setFilter(7,commpany_text)
        self.set_station_row()
    def source_filter(self,sourceid):
        """监控数据过滤热源"""
        self._station_proxy_model.mode='column'
        if sourceid in [1,2,3,4,5]:
            if self._station_proxy_model.filters.get(1):
                del self._station_proxy_model.filters[1]
            
            self._station_proxy_model.setFilter(2,'100'+str(sourceid))
            
        elif sourceid in [6,7,8,9]:
            if self._station_proxy_model.filters.get(2):
                del self._station_proxy_model.filters[2]
            l = [105,114,113,109]
            self._station_proxy_model.setFilter(1,str(l[sourceid-6]))
        else:
            if self._station_proxy_model.filters.get(1) or self._station_proxy_model.filters.get(2):
                self._station_proxy_model.filters.pop(1,None)
                self._station_proxy_model.filters.pop(2,None)
                
                self._station_proxy_model.invalidateFilter()
        self.set_station_row()
    def filter_type(self,i):
        self._station_proxy_model.setFilterKeyColumn(9)
        self._station_proxy_model.setFilterRegularExpression(str(i))
    def showmenu(self,pos:QPoint,tv:QTableView):
        """右键菜单"""
        i = tv.indexAt(pos)

        # print(i.row(),i.column())
        if tv.objectName()=='tv_source':
            return
            
            if i.isValid():
                menu = QMenu()
                menu.setStyleSheet("background-color: rgba(62, 69, 81, 180);    color: #ECF0F1;   ")
                menu.addAction(QIcon(':/icons/images/icons/cil-3d.png'),'工艺参数').triggered.connect(lambda :self.process_jump(i,tv))
                menu.addSeparator()
                menu.addAction(QIcon(':/icons/images/icons/icon_settings.png'),'参数控制').triggered.connect(lambda:self.system_control(tv.model().index(i.row(),0).data(),self.user_init,0))
                menu.addSeparator()
                menu.addAction(QIcon(':/icons/images/icons/cil-movie.png'),'历史数据')
                menu.addSeparator()
                menu.addAction(QIcon(':/icons/images/icons/cil-movie.png'),'报警参数').triggered.connect(lambda:self.set_alarm_ui(tv.model().index(i.row(),0).data(),self.user_init))
                menu.addSeparator()
                l = menu.actions()
                # print(l)
                l[2].setVisible(False)
                l[4].setVisible(False)
                l[6].setVisible(False)
                
                menu.exec(tv.viewport().mapToGlobal(pos))
            return
            
        if i.isValid():
            menu = QMenu()
            menu.setStyleSheet("background-color: rgba(62, 69, 81, 180);    color: #ECF0F1;   ")
            menu.addAction(QIcon(':/icons/images/icons/cil-3d.png'),'工艺参数').triggered.connect(lambda :self.process_jump(i,tv))
            menu.addSeparator()
            menu.addAction(QIcon(':/icons/images/icons/icon_settings.png'),'参数控制').triggered.connect(lambda:self.system_control(tv.model().index(i.row(),0).data(),self.user_init,0))
            # menu.addSeparator()
            # menu.addAction(QIcon(':/icons/images/icons/cil-movie.png'),'历史数据')
            menu.addSeparator()
            menu.addAction(QIcon(':/icons/images/icons/cil-movie.png'),'报警参数').triggered.connect(lambda:self.set_alarm_ui(tv.model().index(i.row(),0).data(),self.user_init))
            menu.addSeparator()
            menu.exec(tv.viewport().mapToGlobal(pos))
    def system_control(self,sysnum,user_init,index = 0):
        """打开设备控制界面"""
        # print('asdfasdfasfasdf')
        # print(user_init)
        # print(self.user_init.get('uuid'))
        if not self.user_init.get('uuid'):
            self.statusbar_text('请登录后控制设备！！')
            return
        system_control_ui = MySystemControl(sysnum,user_init,index)
        
        system_control_ui.exec()
    def set_alarm_ui(self,sysid:str,user_dict:dict):
        """打开报警设置界面"""
        if not user_dict.get('uuid'):
            self.statusbar_text('请登录后设置报警参数！！')
            return
        alarm_ui = MySetAlarmDialog(sysid,user_dict)
        alarm_ui.alarm_signal.connect(self.update_alarm_group)
        
        res = alarm_ui.exec()
    def update_alarm_group(self,alarm_group:dict):
        """更新用户最新的报警设置"""
        self.user_init['alarm_group'] = alarm_group
        # print('update_alarm_group')

    def filter_default(self):
        """清除筛选过滤的选项"""
        l = [widgets.cb_company,widgets.cb_use_type,widgets.cb_source,widgets.cb_sup_type]
        [i.setCurrentIndex(0) for i in l]
        widgets.le_serch.clear()
        
        self._station_proxy_model.filters.clear()
        self._station_proxy_model.invalidateFilter()
        self._station_proxy_model.setFilterRegularExpression('')
        self._station_proxy_model.sort(-1)

    def process_jump(self,i:QModelIndex,tv:QTableView):
        """打开工艺图"""
        # 获得站点编号和数据
        
        row = i.row()
        column = i.column()
        station_num = tv.model().index(row,0).data()
        station_tran = tv.model().index(row,5).data()
        
        tran_num = {
            "1":1,
            "4":0,
            "5":2,
            "1.00":1,
            "4.00":0,
            "5.00":2
            


        }
        
        station_tran_tab = tran_num.get(station_tran)
        if tv == self.ui.tv_source:
            self.ui.tab_source.setCurrentIndex(1)
            # self.ui.    
        # print(station_tran)
        # 获得工艺图跳转界面然后更新该站点数据
        self.ui.tab_station.setCurrentIndex(1)
        # print(station_tran_tab)
        self.ui.tab_station_sw.setCurrentIndex(station_tran_tab)
        station_tran_name = self.ui.tab_station_sw.currentWidget().objectName()
        # widgets.jgybe_station_no.setText(station_num)
        # print(station_tran_name)
        self.get_system_more_info(station_num,station_tran_name)
        # print(i,tv)
        
    def get_system_more_info(self,station_num:str,station_tran_name:str ):
        """创建一个多线程，根据系统编号，获得单个系统的所有运行数据的json数据
            更新工艺图窗口数据和，详细数据打开后显示所有数据，也是实时更新
            当不在工艺图界面时，数据更新停止
            System1:1002271
            .ValueDesc.1.
            .ValueParaDesc.0.
        """
        # print(station_tran_name)
        try:
            del self.process_thread
        except Exception as e :
            pass
        self.process_thread = ProcessThread(station_num,self,station_tran_name)
        self.process_thread.run()
        # 'hshs_btn_set_alarm',   hshs_btn_more_info
        self.btn_set_alarm:QPushButton = self.findChild(QPushButton,f'{station_tran_name}_btn_set_alarm')
        self.btn_more_info:QPushButton = self.findChild(QPushButton,f'{station_tran_name}_btn_more_info')
        try:
            self.btn_set_alarm.clicked.disconnect()
            
            self.btn_more_info.clicked.disconnect()
        except Exception as e:
            pass

        self.btn_set_alarm.clicked.connect(lambda :self.set_alarm_ui(sysid=station_num,user_dict=self.user_init))
        
        self.btn_more_info.clicked.connect(lambda :self.system_more_info(sysid=station_num))

        if station_tran_name !='jgybe':

            btn_xhpump_ctrl:QPushButton =self.findChild(QPushButton,f'{station_tran_name}_btn_xhpump_ctrl') 
            btn_xhpump_ctrl.clicked.disconnect()
            btn_xhpump_ctrl.clicked.connect(lambda:self.system_control(station_num,self.user_init,index = 1))

            btn_value_ctrl:QPushButton =self.findChild(QPushButton,f'{station_tran_name}_btn_value_ctrl') 
            btn_value_ctrl.clicked.disconnect()
            btn_value_ctrl.clicked.connect(lambda:self.system_control(station_num,self.user_init,index = 0))
            return
        btn_bspump_ctrl:QPushButton =self.findChild(QPushButton,f'{station_tran_name}_btn_bspump_ctrl') 
        btn_xhpump_ctrl:QPushButton =self.findChild(QPushButton,f'{station_tran_name}_btn_xhpump_ctrl') 
        btn_value_ctrl:QPushButton =self.findChild(QPushButton,f'{station_tran_name}_btn_value_ctrl') 
        btn_bsvalue_ctrl:QPushButton =self.findChild(QPushButton,f'{station_tran_name}_btn_bsvalue_ctrl') 
        btn_1b2value_ctrl:QPushButton =self.findChild(QPushButton,f'{station_tran_name}_btn_1b2value_ctrl') 
        try :
            btn_1b2value_ctrl.clicked.disconnect()
            btn_bspump_ctrl.clicked.disconnect()
            btn_xhpump_ctrl.clicked.disconnect()
            btn_value_ctrl.clicked.disconnect()
            btn_bsvalue_ctrl.clicked.disconnect()
        except Exception as e:
            pass

        btn_1b2value_ctrl.clicked.connect(lambda:self.system_control(station_num,self.user_init,index = 3))
        btn_bspump_ctrl.clicked.connect(lambda:self.system_control(station_num,self.user_init,index = 2))
        btn_xhpump_ctrl.clicked.connect(lambda:self.system_control(station_num,self.user_init,index = 1))
        btn_value_ctrl.clicked.connect(lambda:self.system_control(station_num,self.user_init,index = 0))
        btn_bsvalue_ctrl.clicked.connect(lambda:self.system_control(station_num,self.user_init,index = 3))

    def system_more_info(self,sysid):
        """打开更多信息界面"""
        # if not user_dict.get('uuid'):
            # self.statusbar_text('请登录后打开！！')
            # return
        system_more_info_ui = MySystemMoreInfo(sysid)
        # system_more_info_ui.show()
        res = system_more_info_ui.exec()
        
    def play_alarm_sound(self):
        # 判断报警声音启动开关，开启声音就发出报警声音，不开启报警就关闭声音

        if self.user_init.get('alarm_sound_enable'):
        # 报警声音启动
            self.effect = QSoundEffect()
            self.effect.setSource(QUrl.fromLocalFile("alarm.wav"))
            self.effect.setLoopCount(3)
            self.effect.setVolume(0.5)
            self.effect.play()
        
    def center_btn(self):
        center_list = [("System2:1002771","guoji"),("System2:1002781","youju"),("System2:1002791","yaguang"),("System2:1002801","tianhong")]
        self.ui.guoji_btn_1b2value_ctrl.clicked.connect(lambda:self.system_control("System2:1002771",self.user_init,index = 3))
        self.ui.guoji_btn_bspump_ctrl.clicked.connect(lambda:self.system_control("System2:1002771",self.user_init,index = 2))
        self.ui.guoji_btn_xhpump_ctrl.clicked.connect(lambda:self.system_control("System2:1002771",self.user_init,index = 1))
        self.ui.guoji_btn_value_ctrl.clicked.connect(lambda:self.system_control("System2:1002771",self.user_init,index = 0))
        self.ui.guoji_btn_bsvalue_ctrl.clicked.connect(lambda:self.system_control("System2:1002771",self.user_init,index = 3))
        self.ui.guoji_btn_set_alarm.clicked.connect(lambda:self.set_alarm_ui("System2:1002771",self.user_init))
        self.ui.guoji_btn_more_info.clicked.connect(lambda:self.system_more_info("System2:1002771"))
        
        self.ui.youju_btn_1b2value_ctrl.clicked.connect(lambda:self.system_control("System2:1002781",self.user_init,index = 3))
        self.ui.youju_btn_bspump_ctrl.clicked.connect(lambda:self.system_control("System2:1002781",self.user_init,index = 2))
        self.ui.youju_btn_xhpump_ctrl.clicked.connect(lambda:self.system_control("System2:1002781",self.user_init,index = 1))
        self.ui.youju_btn_value_ctrl.clicked.connect(lambda:self.system_control("System2:1002778",self.user_init,index = 0))
        self.ui.youju_btn_bsvalue_ctrl.clicked.connect(lambda:self.system_control("System2:1002781",self.user_init,index = 3))
        self.ui.youju_btn_set_alarm.clicked.connect(lambda:self.set_alarm_ui("System2:1002781",self.user_init))
        self.ui.youju_btn_more_info.clicked.connect(lambda:self.system_more_info("System2:1002781"))
        
        
        self.ui.yaguang_btn_1b2value_ctrl.clicked.connect(lambda:self.system_control("System2:1002791",self.user_init,index = 3))
        self.ui.yaguang_btn_bspump_ctrl.clicked.connect(lambda:self.system_control("System2:1002791",self.user_init,index = 2))
        self.ui.yaguang_btn_xhpump_ctrl.clicked.connect(lambda:self.system_control("System2:1002791",self.user_init,index = 1))
        self.ui.yaguang_btn_value_ctrl.clicked.connect(lambda:self.system_control("System2:1002791",self.user_init,index = 0))
        self.ui.yaguang_btn_bsvalue_ctrl.clicked.connect(lambda:self.system_control("System2:1002791",self.user_init,index = 3))
        self.ui.yaguang_btn_set_alarm.clicked.connect(lambda:self.set_alarm_ui("System2:1002791",self.user_init))
        self.ui.yaguang_btn_more_info.clicked.connect(lambda:self.system_more_info("System2:1002791"))
        
        
        self.ui.tianhong_btn_1b2value_ctrl.clicked.connect(lambda:self.system_control("System2:1002801",self.user_init,index = 3))
        self.ui.tianhong_btn_bspump_ctrl.clicked.connect(lambda:self.system_control("System2:1080801",self.user_init,index = 2))
        self.ui.tianhong_btn_xhpump_ctrl.clicked.connect(lambda:self.system_control("System2:1080801",self.user_init,index = 1))
        self.ui.tianhong_btn_value_ctrl.clicked.connect(lambda:self.system_control("System2:1002801",self.user_init,index = 0))
        self.ui.tianhong_btn_bsvalue_ctrl.clicked.connect(lambda:self.system_control("System2:1002801",self.user_init,index = 3))
        self.ui.tianhong_btn_set_alarm.clicked.connect(lambda:self.set_alarm_ui("System2:1002801",self.user_init))
        self.ui.tianhong_btn_more_info.clicked.connect(lambda:self.system_more_info("System2:1002801"))
        return
        for sysid,i in center_list:
            # guoji_btn_more_info
            # print(i)
            current_sysid = sysid
            btn_alarm:QPushButton =self.findChild(QPushButton,f'{i}_btn_set_alarm') 
            btn_info:QPushButton =self.findChild(QPushButton,f'{i}_btn_more_info') 
            btn_1b2value_ctrl:QPushButton =self.findChild(QPushButton,f'{i}_btn_1b2value_ctrl') 
            btn_bspump_ctrl:QPushButton =self.findChild(QPushButton,f'{i}_btn_bspump_ctrl') 
            btn_xhpump_ctrl:QPushButton =self.findChild(QPushButton,f'{i}_btn_xhpump_ctrl') 
            btn_value_ctrl:QPushButton =self.findChild(QPushButton,f'{i}_btn_value_ctrl') 
                                                                #  yaugang_btn_value_ctrl
            btn_bsvalue_ctrl:QPushButton =self.findChild(QPushButton,f'{i}_btn_bsvalue_ctrl') 


            btn_1b2value_ctrl.clicked.connect(lambda sid = current_sysid:self.system_control(sid,self.user_init,index = 3))
            btn_bspump_ctrl.clicked.connect(lambda sid = current_sysid:self.system_control(sid,self.user_init,index = 2))
            btn_xhpump_ctrl.clicked.connect(lambda sid = current_sysid:self.system_control(sid,self.user_init,index = 1))
            btn_value_ctrl.clicked.connect(lambda sid = current_sysid:self.system_control(sid,self.user_init,index = 0))
            btn_bsvalue_ctrl.clicked.connect(lambda sid = current_sysid:self.system_control(sid,self.user_init,index = 3))
            btn_alarm.clicked.connect(lambda sid = current_sysid:self.set_alarm_ui(sid,self.user_init))
            btn_info.clicked.connect(lambda sid = current_sysid:self.system_more_info(sid))
    def modellize(self,l,task_name = 'source'):
        """热源和数据监控更新：
        接受后台的实时热源和站点监控数据，填充到表格"""
        l = json.loads(l)
        if task_name =='source':
            view = self.ui.tv_source
            model = self.source_model
            proxymodel = self._source_proxy_model
        elif task_name =='station':
            view = self.ui.tv_station
            model = self.station_model
            proxymodel = self._station_proxy_model
        if view.model() is None:
            # print('初始化模型',task_name)
            header = l.pop(0)
            model.setHorizontalHeaderLabels(header)
            for i,j in enumerate(header):

                model.horizontalHeaderItem(i).setFont(QFont('微软雅黑',12))
            # view.viewport().update()
            for row_index,i in enumerate(l):
                l1=list()
                for j in i:
                    if (type(j)==float):
                        j = round(j,3)
                    it = QStandardItem(str(j))
                    it.setTextAlignment(Qt.AlignmentFlag.AlignRight |Qt.AlignmentFlag.AlignCenter)
                    if j =="异常":
                        it.setForeground(QColor('red'))
                    # it.setSizeHint(QSize(-1,60))
                    it.setFont(QFont('微软雅黑',12))
                    l1.append(it)
                model.appendRow(l1)
                
            view.setModel(proxymodel)
            for i in range(0,len(l)):
            # view.horizontalHeader().setFont(QFont('微软雅黑',16))
                view.setRowHeight(i,view.rowHeight(i)+20)
            if task_name == 'station':
                for i in range(0,9):
                    # 隐藏前7列基础信息
                    # continue
                    view.setColumnHidden(i,True)
            # 自动调整行高列宽
            view.resizeColumnsToContents()
            # view.resizeRowsToContents()
            # view.setRowHeight(1,view.rowHeight(1)+100)
            view.verticalScrollBar().setStyleSheet(
            """
                QScrollBar:vertical {
                width: 15px;
            }
                QScrollBar:horizontal {
                width: 15px;
            }
            """

            )
        else:
            # print('更新模型',task_name)
            header = l.pop(0)
            c = model.columnCount()
            r = model.rowCount()
            # model.blockSignals(True)
            # model.beginResetModel()
            for i in range(0,r):
                # print(i)
                for j in range(0,len(l[i])):
                    if l[i][j]=='异常':
                        # model.item(i,j).foreground().color()
                        
                        model.item(i,j).setForeground(QColor('red'))
                    elif l[i][j]=='正常':
                        model.item(i,j).setForeground(QColor('white'))

                    # print(i,j)
                    if ((type(l[i][j])==float) or (type(l[i][j])==int)):
                        l[i][j] = round(l[i][j],2)
                        # print(l[i][j])
                        item_value = "{:.2f}".format(l[i][j])
                        model.setData(model.index(i,j),item_value)
                        continue
                    model.setData(model.index(i,j),l[i][j])
                    # print(model.item(0,0).foreground().color().colorNames())
                
            # model.blockSignals(False)
            # model.endResetModel()
        # font = self.ui.tv_station.font()
        # font.setPointSize(35)
        # self.ui.tv_station.setFont(font)
    

    def statusbar_text(self,text=''):
        """状态栏显示内容"""
        self.statusbar_t = QTimer()
        widgets.creditsLabel.setText(text)
        widgets.creditsLabel.setStyleSheet('background-color:#6272a5;color:#ffffff')

        self.statusbar_t.singleShot(5000,self.statusbar_blink)
    def statusbar_blink(self):
        """状态栏闪烁"""
        widgets.creditsLabel.clear()
        widgets.creditsLabel.setStyleSheet('background-color:#2c313a')#21252b

        
# user define or test function####################################################################################################

    # BUTTONS CLICK
    # Post here your functions for clicked buttons
    # ///////////////////////////////////////////////////////////////
    def buttonClick(self):
        # GET BUTTON CLICKED
        btn = self.sender()
        btnName = btn.objectName()

        # SHOW HOME PAGE
        if btnName == "btn_home":
            widgets.stackedWidget.setCurrentWidget(widgets.home)
            UIFunctions.resetStyle(self, btnName)
            btn.setStyleSheet(UIFunctions.selectMenu(btn.styleSheet()))


        # SHOW WIDGETS PAGE
        if btnName == "btn_widgets":
            widgets.stackedWidget.setCurrentWidget(widgets.widgets)
            UIFunctions.resetStyle(self, btnName)
            btn.setStyleSheet(UIFunctions.selectMenu(btn.styleSheet()))

        # 增加新界面
        if btnName == "btn_new":
            widgets.stackedWidget.setCurrentWidget(widgets.new_page) # SET PAGE
            UIFunctions.resetStyle(self, btnName) # RESET ANOTHERS BUTTONS SELECTED
            btn.setStyleSheet(UIFunctions.selectMenu(btn.styleSheet())) # SELECT MENU
        # 增加热源界面
        if btnName == "btn_source":
            widgets.stackedWidget.setCurrentWidget(widgets.source) # SET PAGE
            UIFunctions.resetStyle(self, btnName) # RESET ANOTHERS BUTTONS SELECTED
            btn.setStyleSheet(UIFunctions.selectMenu(btn.styleSheet())) # SELECT MENU
            widgets.tab_source.setCurrentIndex(0)
        # 增加站点界面
        if btnName == "btn_station":
            widgets.stackedWidget.setCurrentWidget(widgets.station) # SET PAGE
            UIFunctions.resetStyle(self, btnName) # RESET ANOTHERS BUTTONS SELECTED
            btn.setStyleSheet(UIFunctions.selectMenu(btn.styleSheet())) # SELECT MENU
            widgets.tab_station.setCurrentIndex(0)
        # 增加全网界面
        if btnName == "btn_netbalance":
            widgets.stackedWidget.setCurrentWidget(widgets.netbalance) # SET PAGE
            UIFunctions.resetStyle(self, btnName) # RESET ANOTHERS BUTTONS SELECTED
            btn.setStyleSheet(UIFunctions.selectMenu(btn.styleSheet())) # SELECT MENU
        # 增加报警界面
        if btnName == "btn_alarm":
            widgets.stackedWidget.setCurrentWidget(widgets.alarm) # SET PAGE
            UIFunctions.resetStyle(self, btnName) # RESET ANOTHERS BUTTONS SELECTED
            btn.setStyleSheet(UIFunctions.selectMenu(btn.styleSheet())) # SELECT MENU
            now = QDateTime().date().currentDate()
            before = now.addDays(-7)
            self.ui.date_alarm_end_time.setDate(now)
            self.ui.date_alarm_start_time.setDate(before)
 
        # 增加工艺界面
        if btnName == "btn_process":
            widgets.stackedWidget.setCurrentWidget(widgets.process) # SET PAGE
            UIFunctions.resetStyle(self, btnName) # RESET ANOTHERS BUTTONS SELECTED
            btn.setStyleSheet(UIFunctions.selectMenu(btn.styleSheet())) # SELECT MENU
        # 中心站画面
        if btnName == "btn_center":
            widgets.stackedWidget.setCurrentWidget(widgets.center) # SET PAGE
            UIFunctions.resetStyle(self, btnName) # RESET ANOTHERS BUTTONS SELECTED
            btn.setStyleSheet(UIFunctions.selectMenu(btn.styleSheet())) # SELECT MENU
        # 历史数据画面
        if btnName == "btn_history":
            widgets.stackedWidget.setCurrentWidget(widgets.history) # SET PAGE
            UIFunctions.resetStyle(self, btnName) # RESET ANOTHERS BUTTONS SELECTED
            btn.setStyleSheet(UIFunctions.selectMenu(btn.styleSheet())) # SELECT MENU
        # 用户自定义功能区
        if btnName == "btn_userdefine":
            widgets.stackedWidget.setCurrentWidget(widgets.userdefine) # SET PAGE
            UIFunctions.resetStyle(self, btnName) # RESET ANOTHERS BUTTONS SELECTED
            btn.setStyleSheet(UIFunctions.selectMenu(btn.styleSheet())) # SELECT MENU
        # 日志画面
        if btnName == "btn_logs":
            widgets.stackedWidget.setCurrentWidget(widgets.logs) # SET PAGE
            UIFunctions.resetStyle(self, btnName) # RESET ANOTHERS BUTTONS SELECTED
            btn.setStyleSheet(UIFunctions.selectMenu(btn.styleSheet())) # SELECT MENU

            now = QDateTime().date().currentDate()
            before = now.addDays(-7)
            self.ui.dte_operate_log_stop_date.setDate(now)
            self.ui.dte_operate_log_start_date.setDate(before)
            
 
        if btnName == "btn_save":
            print("Save BTN clicked!")

        # PRINT BTN NAME
        print(f'Button "{btnName}" pressed!')


    # RESIZE EVENTS
    # ///////////////////////////////////////////////////////////////
    def resizeEvent(self, event):
        # Update Size Grips
        UIFunctions.resize_grips(self)
        # pass

    # MOUSE CLICK EVENTS
    # ///////////////////////////////////////////////////////////////
    def mousePressEvent(self, event):
        # SET DRAG POS WINDOW
        self.dragPos = event.globalPosition().toPoint()
        print(self.dragPos)

        # PRINT MOUSE EVENTS
        if event.buttons() == Qt.LeftButton:
            print('Mouse click: LEFT CLICK')
        if event.buttons() == Qt.RightButton:
            print('Mouse click: RIGHT CLICK')
    def closeEvent(self, event):
        
        return super().closeEvent(event)
if __name__ == "__main__":

    app = QApplication(sys.argv)
    app.setWindowIcon(QIcon(":/icons/images/icons/company_logo.png"))
    # app.setStyle('windows')
    window = MainWindow()
    window.activateWindow()
    sys.exit(app.exec())
